#pragma once
#include "DataManager.hpp"
#include "httplib.h"

namespace Cloude
{
	/*
		构建http客户端，向服务器发起备份请求，将指定目录下的文件进行备份
		使用httplib构建客户端
	*/
	using std::string;
	using std::endl;
	using std::cout;

	const string server_ip = "192.168.8.10";
	const int server_port = 8888;
	class Backup
	{
	private:
		string _back_dir;
		DataManager* _dataM;
		//httplib::Client _client;
	public:
		Backup(const string& data_file,const string& back_dir)
			:_back_dir(back_dir)
		{
			FileUtil fb(back_dir);
			fb.CreateDirectorY();
			_dataM = new DataManager(data_file);
		}

		string GetFileId(const string& filename)
		{
			FileUtil fu(filename);
			std::stringstream ss;
			// file_id --> name + size + mtime
			ss << fu.FileName() << "-" << fu.GetFileSize() << fu.GetMTime();
			return ss.str();
		}
		// 2.1 如果文件不存在，需要备份
		// 2.2 如何文件存在，但FileId不同，也需要备份
		bool IsNeedBackup(const string& filename)
		{
			string file_id;
			// 备份文件不存在
			if (_dataM->GetIdByFileName(filename, &file_id) == false)
			{
				return true;
			}
			// 备份文件存在，则要判断file_id 是否是否在变化
			// file_id没变，则不需要备份
			if (file_id == GetFileId(filename))
			{
				return false;
			}
			else
			{
				// file_id 变了
				// 这里有个问题，如果备份的文件很大，上传到服务器备份是需要花时间的，
				// 所以不能仅仅通过 file_id的变化，来判断是否要备份，				
				// 应该是要在一个限定时间内，file_id 变化了，不需要备份，超过这个时间则需要备份
				// 另一种判断： 判断的这个文件是否被其他进程占用
				FileUtil fu(filename);
				if (time(nullptr) - fu.GetMTime() > 3) // 超过3秒后，file_id变了需要备份
					return true;
				else //3秒内，file_id变了不需要备份
					return false;

			}

		}
		
		
		bool UpLoad(const string& filename)
		{
			// 必须要获取纯文件名，因为linux与windows路径不兼容
			string name = FileUtil(filename).FileName();

			httplib::Client client(server_ip, server_port);
			cout << name << " need backup " << endl;

			//3.构建上传请求
			httplib::MultipartFormDataItems items;

			httplib::MultipartFormData data;
			// 这个字段需要和服务器上处理/upload请求方法中对应起来
			// has_file("file") 存在一个file表单
			data.name = "file";
			FileUtil fu(filename);
			fu.GetContent(&data.content);
			data.filename = name;

			// 未来我们备份的数据是不知道是哪种类型的
			// 所以我们得需要用字节流
			data.content_type = "application/octet-stream";
			items.push_back(data);
			auto res = client.Post("/upload", items);
			if (!res || res->status != 400 || res->status != 404) // 这里是单个文件单个表单的发送的
			{
				return true;
			}
			return false;

		}
		void RunMoudle()
		{
			while (true)
			{
				// 1.获取备份目录下的所有文件
				FileUtil fb(_back_dir);
				std::vector<string> filenames;
				fb.ScanDirectory(&filenames);
				// ScanDir获取的是路径
				for (auto& filename : filenames)
				{
					// 纯文件名，因为linux与windows路径不兼容，我们必须要纯文件名
					string name = FileUtil(filename).FileName();
					// 2.判断是否需要备份
					if (IsNeedBackup(name) == false)
						continue;
					// 3. 上传
					if (UpLoad(filename) == true)
					{
						// 4. 备份成功，插入表中
						cout << name << " backup successful" << endl;
						_dataM->Insert(name, GetFileId(name));
						_dataM->Print();
					}

				}
				// 一秒检测一次
				Sleep(1000);
				cout << "---------------------------------------------------" << endl;
			}
		}


	};
}